#include "arp_handle.h"
#include "arp_handle.h"
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <stdlib.h>       // free
#include <net/ethernet.h> // struct ether_header
#include <netinet/in.h>   // ntohs
#include <arpa/inet.h>    // inet_ntop
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>

unsigned char mac_broadcast_mac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; // 以太网广播地址
unsigned char arp_broadcast_mac[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // arp广播地址

arp_list_head *arp_head; // arp表头
pthread_rwlock_t rwlock; // 读写锁

/****************************************************************
函数:
功能: 发送arp报文
参数: 文件描述符 操作标识(1请求报文 2应答) 目的ip 目的mac 网卡名
返回值: 无
*****************************************************************/
int arp_send(int sockfd, unsigned short op, unsigned char dst_ip[4], unsigned char dst_mac[6], INTERFACE *eth)
{
    char buf[42] = "";
    // mac报文
    struct ether_header *eth_hdr = (struct ether_header *)buf;
    memcpy(eth_hdr->ether_dhost, dst_mac, 6);
    memcpy(eth_hdr->ether_shost, eth->mac, 6);
    eth_hdr->ether_type = htons(0x0806);

    // arp报文
    ARPHDR *arp_hdr = (ARPHDR *)(buf + 14);
    arp_hdr->ar_hrd = htons(1);             // 硬件类型
    arp_hdr->ar_pro = htons(0x0800);        // 协议类型 IP
    arp_hdr->ar_hln = 6;                    // 硬件地址长度(mac长度)
    arp_hdr->ar_pln = 4;                    // 协议地址长度(IP长度)
    arp_hdr->ar_op = htons(op);             // op操作码 1请求 2应答
    memcpy(arp_hdr->__ar_sha, eth->mac, 6); // 源mac地址
    memcpy(arp_hdr->__ar_sip, eth->ip, 4);  // 源IP 需要修改对应IP的mac

    // 如果mac是广播地址则arp的mac是全0
    if (memcpy(dst_mac, mac_broadcast_mac, 6) == 0)
    {
        memcpy(arp_hdr->__ar_tha, arp_broadcast_mac, 6); // 广播mac地址
    }
    else
    {
        memcpy(arp_hdr->__ar_tha, dst_mac, 6); // 目的mac地址
    }

    memcpy(arp_hdr->__ar_tip, dst_ip, 4); // 目的IP 谁的arp表的IP

    return send_msg(sockfd, buf, sizeof(buf), eth->name);
}

/*******************************************************
函数: void *arp_recv(void *arg)
功能: 接收arp报文
参数: typedef struct MSG
    {
        int fd;                          // 描述符
        unsigned char data[MAXDATASIZE]; // 原始报文数据
    } raw_msg;
返回值: 无
********************************************************/
void *arp_recv(void *arg)
{
    raw_msg *msg = (raw_msg *)arg;
    // 解析mac报文
    struct ether_header *eth_hdr = (struct ether_header *)(msg->data);

    // 解析arp报文
    ARPHDR *arp_hdr = (ARPHDR *)(msg->data + 14);

    // 校验源mac和目的mac是否一致 不一致则不合法应当抛弃
    if ((memcmp(eth_hdr->ether_dhost, arp_hdr->__ar_tha, 6) != 0) ||
        (memcmp(eth_hdr->ether_shost, arp_hdr->__ar_sha, 6) != 0))
    {
        free(arg);
        return NULL;
    }

    // 判断arp操作类型
    unsigned short op = ntohs(arp_hdr->ar_op);
    if (op == 2) // 应答
    {
        // 记录到arp链表中
        insert_arp_list(arp_hdr->__ar_sip, arp_hdr->__ar_sha);
        // printf("2 ip=%d.%d.%d.%d\n", arp_hdr->__ar_sip[0], arp_hdr->__ar_sip[1], arp_hdr->__ar_sip[2], arp_hdr->__ar_sip[3]);
    }
    else if (op == 1) // 请求 需要回复消息
    {
        // 如果目的ip是本机才需要回复
        if (is_local(arp_hdr->__ar_tip) == 0)
        {
            // 查找源ip是否在网段中
            INTERFACE *src_eth = find_ether(arp_hdr->__ar_sip);
            if (NULL == src_eth) // 不在网段中则抛弃
            {
                free(arg);
                return NULL;
            }
            // 组件应答报文
            // 文件描述符 操作标识 目的ip 目的mac 网卡信息
            arp_send(msg->fd, 2, arp_hdr->__ar_tip, arp_hdr->__ar_tha, src_eth);
        }
    }

    free(arg); // 使用完释放数据
    return NULL;
}

/**********************************************
函数: arp_list_head* init_arp_list_head()
功能: 初始化arp链表头
参数: 无
返回值: 失败返回NULL
***********************************************/
arp_list_head *init_arp_list_head()
{
    // 初始化读写锁 控制数据写入和读取
    pthread_rwlock_init(&rwlock, NULL);

    arp_head = (arp_list_head *)malloc(sizeof(arp_list_head));
    if (NULL == arp_head)
    {
        perror("malloc arp_list_head");
        arp_head = NULL;
        return NULL;
    }
    arp_head->size = 0;
    arp_head->next = NULL;
    return arp_head;
}
/*******************************************************************
函数: int insert_arp_list(unsigned char ip[4], unsigned char mac[6])
功能: 插入arp节点数据
参数: ip、mac
返回值: 失败返回-1
********************************************************************/
int insert_arp_list(unsigned char ip[4], unsigned char mac[6])
{
    if (NULL == arp_head)
    {
        printf("arp_head is null\n");
        return -1;
    }
    arp_node *tmp = arp_head->next;
    pthread_rwlock_wrlock(&rwlock); // 申请写锁
    // 判断ip是否存在，如果存在修改mac
    while (tmp != NULL)
    {
        if (memcmp(tmp->ip.ip_ch, ip, 4) == 0) // 如果ip相同
        {

            memcpy(tmp->mac, mac, 6);       // 修改原有mac地址
            pthread_rwlock_unlock(&rwlock); // 解锁
            return 0;
        }
        if (tmp->next == NULL) // 如果是最后一个元素
        {
            break;
        }
        tmp = tmp->next;
    }
    arp_node *p = (arp_node *)malloc(sizeof(arp_node));
    if (NULL == p)
    {
        perror("malloc");
        pthread_rwlock_unlock(&rwlock); // 解锁
        return -1;
    }
    memcpy(p->ip.ip_ch, ip, 4);
    memcpy(p->mac, mac, 6);
    p->next = NULL;
    if (arp_head->next == NULL)
        arp_head->next = p;
    else
        tmp->next = p;
    arp_head->size++;
    pthread_rwlock_unlock(&rwlock); // 解锁
    return 0;
}
/**********************************************
函数: void print_arp_list()
功能: 输出apr表
参数: 无
返回值: 无
***********************************************/
void print_arp_list()
{
    // 头节点存在并且有数据
    if (arp_head != NULL && arp_head->size > 0)
    {
        pthread_rwlock_rdlock(&rwlock); // 申请读锁
        printf("=======================arp=======================\n");
        arp_node *tmp = arp_head->next;
        while (tmp != NULL)
        {
            unsigned char buf[16] = "";
            inet_ntop(AF_INET, &tmp->ip.ip_in, buf, sizeof(buf));
            printf("IP: %s  MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", buf, tmp->mac[0],
                   tmp->mac[1], tmp->mac[2], tmp->mac[3], tmp->mac[4], tmp->mac[5]);
            tmp = tmp->next;
        }
        printf("=======================arp=======================\n");
        pthread_rwlock_unlock(&rwlock); // 释放读锁
    }
    else
        printf("arp表为空\n");
}
/**********************************************
函数: arp_node * find_arp_ip(unsigned char ip[4])
功能: 查询mac地址
参数: ip地址
返回值: 失败返回NULL 成功返回arp表节点
***********************************************/
arp_node *find_arp_ip(unsigned char ip[4])
{
    if (NULL == arp_head)
    {
        printf("arp_head is null\n");
        return NULL;
    }
    pthread_rwlock_rdlock(&rwlock); // 申请读锁
    arp_node *tmp = arp_head->next;
    while (tmp != NULL)
    {
        if (memcmp(tmp->ip.ip_ch, ip, 4) == 0) // 如果ip相同
        {
            pthread_rwlock_unlock(&rwlock); // 释放读锁
            return tmp;
        }
        if (tmp->next == NULL) // 如果是最后一个元素
        {
            break;
        }
        tmp = tmp->next;
    }
    pthread_rwlock_unlock(&rwlock); // 释放读锁
    return NULL;
}